# Load in data
hires_2019_clean <- read_csv('../clean_data/hires_2019_clean.csv')
Rows: 124446 Columns: 19
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr   (4): start_station_name, start_station_description, end_station_name, end_station_description
dbl  (11): duration, start_station_id, start_station_latitude, start_station_longitude, end_station_id, end_station...
date  (2): start_date, end_date
time  (2): start_time, end_time

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
rain_2019_clean <- read_csv('../clean_data/rain_2019_clean.csv')
Rows: 365 Columns: 2
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
dbl  (1): rainfall_mm
date (1): start_date

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# number of stations in total: 164
hires_2019_clean %>% 
  distinct(start_station_id) %>% 
  count()

hires_2019_clean %>% 
  distinct(end_station_id) %>% 
  count()
# visualising use by month
hires_2019_clean %>% 
  mutate(month = month(start_date, label = TRUE), .before = 1) %>% 
  group_by(month) %>% 
  summarise(count = n()) %>%
  ggplot() +
  aes(x = month, y = count) +
  geom_col(fill = "#F27F1B") +
  geom_text(aes(label = count), vjust = 2, colour = "white", size = 3.5) +
  labs(x = "\nMonth",
       y = "Number of journeys\n",
       title = "Total number of bike journeys by month (2019)",
       subtitle = "Total = 124446 journeys\n\n") +
  scale_y_discrete(expand = c(0,1), limits = c(0, 5000, 10000, 15000)) +
  theme_minimal() +
  theme(title = element_text(size = 12),
        axis.text = element_text(size = 10),
        axis.title.x = element_text(size = 10),
        axis.title.y = element_text(size = 10),
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        panel.background = element_blank(), 
        axis.line = element_line(colour = "black"))
hires_2019_clean %>% 
  mutate(day = wday(start_date, label = TRUE), .before = 1) %>% 
  group_by(day) %>% 
  summarise(count = n()) %>%
  ggplot() +
  aes(x = day, y = count) +
  geom_col(fill = "#F27F1B") +
  geom_text(aes(label = count), vjust = 2, colour = "white", size = 3.5) +
  labs(x = "\nDay of week",
       y = "Number of journeys\n",
       title = "Total number of bike journeys by day of week (2019)") +
  scale_y_discrete(expand = c(0,1), limits = c(0, 5000, 10000, 15000)) +
  theme_minimal() +
  theme(title = element_text(size = 12),
        axis.text = element_text(size = 10),
        axis.title.x = element_text(size = 10),
        axis.title.y = element_text(size = 10),
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        panel.background = element_blank(), 
        axis.line = element_line(colour = "black"))
Warning: Continuous limits supplied to discrete scale.
Did you mean `limits = factor(...)` or `scale_*_continuous()`?

Mapping out stations

# create smaller dataset for map
map_data <- hires_2019_clean %>% 
  select(start_station_longitude, start_station_latitude, start_station_id, start_station_name, start_elevation) %>% 
  distinct(start_station_id, .keep_all = TRUE)

# create custom icon for bike hire stations
bike  <-  makeIcon("../www/bicycle-outline.png")

# map station data using leaflet app
map_data %>% 
  leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addTiles(providers$CartoDB.Positron) %>%
  addMarkers(~start_station_longitude, ~start_station_latitude, 
             icon = ~bike,
             #clusterOptions = markerClusterOptions(),
             popup = ~paste0("Station ID: ", start_station_id,
                              "<br>Name: ", start_station_name,
                              "<br>Elevation (m): ", start_elevation))

  # addCircles(lng = ~start_station_longitude,
  #            lat = ~start_station_latitude,
  #            color = "#F27F1B",
  #            popup = ~paste0("Station ID: ", start_station_id,
  #                            "<br>Name: ", start_station_name,
  #                            "<br>Elevation (m): ", start_elevation))

Journeys based on elevation

68622 downhill journeys 43774 uphill journeys 12050 flat journeys

# downhill vs uphill vs flat journeys
# based on elevation of start and end stations

# 68622 downhill journeys
hires_2019_clean %>% 
  filter(elevation_diff < 0) %>% 
  count()

# 43774 uphill journeys
hires_2019_clean %>% 
  filter(elevation_diff > 0) %>% 
  count()

# 12050 flat journeys
hires_2019_clean %>% 
  filter(elevation_diff == 0) %>% 
  count()
get_elev_raster()

Journeys based on weather

According to www.statista.com “A rainday is when one millimetre or more of rain occurs in a day.” Based on this I have classified rainy days as days where rainfall as recorded by www.power.larc.nasa.gov/ was equal to or over 1mm in Edinburgh.

Hypothesis Test

# calculate the p-value and compare to α value
p_value <- null_distribution %>%
  get_p_value(obs_stat = observed_stat, direction = "left")
Warning: Please be cautious in reporting a p-value of 0. This result is an approximation based on the number of `reps` chosen in the `generate()` step. See `?get_p_value()` for more information.
# hypothesis test
# α = 0.05
# H0 - Rain makes no difference to bike hires
# H1 - Rain has an impact on bike hires
# Type of test is one-sample proportion, right-sided.
# 
# p value = 0 
# 
# The p-value being near to 0 means it is less than α, and so we should reject H0 based on our data. The result is statistically significant in favour of H1, that rain may impact bike hire numbers.

# rain_day <- hires_2019_clean %>%
#   group_by(start_date) %>% 
#   mutate(rain_day = rainfall_mm >= 1) %>% 
#   select(start_date, rain_day) %>% 
#   count(start_date, rain_day)
# 
# null_distribution <- rain_day %>%
#   specify(response = rain_day, success = "TRUE") %>%
#   hypothesize(null = "point", p = 0.05) %>%
#   generate(reps = 10000, type = "draw") %>%
#   calculate(stat = "prop")
# 
# obs_stat <- rain_day %>%
#   specify(response = rain_day, success = "TRUE") %>%
#   calculate(stat = "prop")
# 
# null_distribution %>%
#   visualise() +
#   shade_p_value(direction = "right", obs_stat = obs_stat)
# 
# null_distribution %>%
#   get_p_value(direction = "right", obs_stat = obs_stat)
# bootstrapped hypothesis
# α = 0.05
# H0 - Rain makes no difference to bike hires
# H1 - Rain has an impact on bike hires

# rain_day_flag <- rain_day %>%
#   mutate(rain_day_flag = if_else(rain_day == "TRUE", 1, 0))
# 
# null_distribution <- rain_day_flag %>%
#   specify(response = rain_day_flag) %>%
#   hypothesize(null = "point", mu = 0.05) %>%
#   generate(reps = 10000, type = "bootstrap") %>%
#   calculate(stat = "mean")
# 
# null_distribution %>%
#   visualise() +
#   shade_p_value(direction = "right", obs_stat = obs_stat)
# 
# null_distribution %>%
#   get_p_value(direction = "right", obs_stat = obs_stat)

Independence Hypothesis Test On Rainy day data

Does a rainy day have an effect on bike hires

α = 0.05 H0 - Rain makes no difference to bike hires H1 - Rain has an impact on bike hires

The p-value ≤ α, so I reject the null hypothesis H0 in favour of the alternative hypothesis H1, that rain may have an effect on bike hires.

Rainy Days in 2019 = 181 Rainy journeys = 58073 Non rainy journeys = 66373

# count the number of days with rainfall equal to or over 1mm
rain_2019_clean %>% 
  filter(rainfall_mm >= 1) %>% 
  count()

# journeys based on rainfall
# based on daily precipitation
hires_2019_clean %>% 
  filter(rainfall_mm >= 1) %>% 
  count()

hires_2019_clean %>% 
  filter(rainfall_mm < 1) %>% 
  count()

Time of Day analysis

Gym Bunnies - before 7am: 7783 23.07 mins
Morning Commuters - 7am to 9am: 12452 17.87 mins
Day Trippers - 9am to 5pm: 66880 29.75 mins
Homeward Bounders - 5pm to 6.30pm: 14961 23.86 mins
Evening Movers - 6.30pm to 10pm: 16815 23.5 mins
Pub Ponies - 10pm to Midnight: 5555 20.67 mins

Average journey time overall is 26.18 minutes

# Gym Bunnies - before 7am
hires_2019_clean %>% 
  mutate(start_time = as.character(start_time), end_time = as.character(end_time)) %>% 
  filter(start_time <= "07:00:00") %>% 
  mutate(mean_duration = round(mean(duration), 2)) %>% 
  count(mean_duration)

# Morning Commuters - 7am to 9am
hires_2019_clean %>% 
  mutate(start_time = as.character(start_time), end_time = as.character(end_time)) %>% 
  filter(start_time > "07:00:00", start_time <= "09:00:00") %>% 
  mutate(mean_duration = round(mean(duration), 2)) %>% 
  count(mean_duration)

# Day Trippers - 9am to 5pm
hires_2019_clean %>% 
  mutate(start_time = as.character(start_time), end_time = as.character(end_time)) %>% 
  filter(start_time > "09:00:00", start_time < "17:00:00") %>% 
  mutate(mean_duration = round(mean(duration), 2)) %>% 
  count(mean_duration)

# Homeward Bounders - 5pm to 6.30pm
hires_2019_clean %>% 
  mutate(start_time = as.character(start_time), end_time = as.character(end_time)) %>% 
  filter(start_time >= "17:00:00", start_time <= "18:30:00") %>% 
  mutate(mean_duration = round(mean(duration), 2)) %>% 
  count(mean_duration)

# Evening Movers - 6.30pm to 10pm
hires_2019_clean %>% 
  mutate(start_time = as.character(start_time), end_time = as.character(end_time)) %>% 
  filter(start_time > "18:30:00", start_time < "22:00:00") %>% 
  mutate(mean_duration = round(mean(duration), 2)) %>% 
  count(mean_duration)

# Pub Ponies - 10pm to Midnight
hires_2019_clean %>% 
  mutate(start_time = as.character(start_time), end_time = as.character(end_time)) %>% 
  filter(start_time >= "22:00:00") %>% 
  mutate(mean_duration = round(mean(duration), 2)) %>% 
  count(mean_duration)

# Average journey length
hires_2019_clean %>% 
  mutate(mean_duration = round(mean(duration), 2)) %>% 
  count(mean_duration)
NA
hires_2019_clean %>% 
  select(start_time) %>%
  group_by(start_time) %>% 
  count() %>%
  ggplot() +
  geom_line(aes(start_time, n), col = "#F27F1B") +
  labs(x = "\nTime of Day",
       y = "Number of Journeys\n",
       title = "Start time of journeys") +
  theme_minimal() +
  theme(title = element_text(size = 12),
        axis.text = element_text(size = 10),
        axis.title.x = element_text(size = 10),
        axis.title.y = element_text(size = 10),
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        panel.background = element_blank(), 
        axis.line = element_line(colour = "black"))

# trying a raster image of elevation
ggplot() +
  geom_raster(data = new_elevation_raster, aes(x = x, y = y)) +
  geom_sf(data = elevation_raster, color = "white") +
  coord_sf() +
  scale_fill_viridis_c() +
  labs(title = " ", x = " ", y = " ", fill = " ")
LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdCB3b3JrYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3IgaW5jbHVkZT1GQUxTRX0KIyBsb2FkIGxpYnJhcmllcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoZWxldmF0cikKbGlicmFyeShyZ2RhbCkKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoaW5mZXIpCmxpYnJhcnkoc2YpCmxpYnJhcnkocmdlb2JvdW5kYXJpZXMpCmxpYnJhcnkobWFwZGVjaykKCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRX0KIyBMb2FkIGluIGRhdGEKaGlyZXNfMjAxOV9jbGVhbiA8LSByZWFkX2NzdignLi4vY2xlYW5fZGF0YS9oaXJlc18yMDE5X2NsZWFuLmNzdicpCnJhaW5fMjAxOV9jbGVhbiA8LSByZWFkX2NzdignLi4vY2xlYW5fZGF0YS9yYWluXzIwMTlfY2xlYW4uY3N2JykKCgpgYGAKCgoKYGBge3J9CiMgbnVtYmVyIG9mIHN0YXRpb25zIGluIHRvdGFsOiAxNjQKaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgZGlzdGluY3Qoc3RhcnRfc3RhdGlvbl9pZCkgJT4lIAogIGNvdW50KCkKCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIGRpc3RpbmN0KGVuZF9zdGF0aW9uX2lkKSAlPiUgCiAgY291bnQoKQpgYGAKCgpgYGB7cn0KIyB2aXN1YWxpc2luZyB1c2UgYnkgbW9udGgKaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgbXV0YXRlKG1vbnRoID0gbW9udGgoc3RhcnRfZGF0ZSwgbGFiZWwgPSBUUlVFKSwgLmJlZm9yZSA9IDEpICU+JSAKICBncm91cF9ieShtb250aCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gbW9udGgsIHkgPSBjb3VudCkgKwogIGdlb21fY29sKGZpbGwgPSAiI0YyN0YxQiIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY291bnQpLCB2anVzdCA9IDIsIGNvbG91ciA9ICJ3aGl0ZSIsIHNpemUgPSAzLjUpICsKICBsYWJzKHggPSAiXG5Nb250aCIsCiAgICAgICB5ID0gIk51bWJlciBvZiBqb3VybmV5c1xuIiwKICAgICAgIHRpdGxlID0gIlRvdGFsIG51bWJlciBvZiBiaWtlIGpvdXJuZXlzIGJ5IG1vbnRoICgyMDE5KSIsCiAgICAgICBzdWJ0aXRsZSA9ICJUb3RhbCA9IDEyNDQ0NiBqb3VybmV5c1xuXG4iKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQgPSBjKDAsMSksIGxpbWl0cyA9IGMoMCwgNTAwMCwgMTAwMDAsIDE1MDAwKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUodGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkKCmBgYAoKYGBge3J9CiMgdmlzdWFsaXNlIHVzZSBieSBkYXkgb2YgdGhlIHdlZWsKCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIG11dGF0ZShkYXkgPSB3ZGF5KHN0YXJ0X2RhdGUsIGxhYmVsID0gVFJVRSksIC5iZWZvcmUgPSAxKSAlPiUgCiAgZ3JvdXBfYnkoZGF5KSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBkYXksIHkgPSBjb3VudCkgKwogIGdlb21fY29sKGZpbGwgPSAiI0YyN0YxQiIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY291bnQpLCB2anVzdCA9IDIsIGNvbG91ciA9ICJ3aGl0ZSIsIHNpemUgPSAzLjUpICsKICBsYWJzKHggPSAiXG5EYXkgb2Ygd2VlayIsCiAgICAgICB5ID0gIk51bWJlciBvZiBqb3VybmV5c1xuIiwKICAgICAgIHRpdGxlID0gIlRvdGFsIG51bWJlciBvZiBiaWtlIGpvdXJuZXlzIGJ5IGRheSBvZiB3ZWVrICgyMDE5KSIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwxKSwgbGltaXRzID0gYygwLCA1MDAwLCAxMDAwMCwgMTUwMDApKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpKQpgYGAKCgojIyMgTWFwcGluZyBvdXQgc3RhdGlvbnMKCmBgYHtyfQojIGNyZWF0ZSBzbWFsbGVyIGRhdGFzZXQgZm9yIG1hcAptYXBfZGF0YSA8LSBoaXJlc18yMDE5X2NsZWFuICU+JSAKICBzZWxlY3Qoc3RhcnRfc3RhdGlvbl9sb25naXR1ZGUsIHN0YXJ0X3N0YXRpb25fbGF0aXR1ZGUsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X3N0YXRpb25fbmFtZSwgc3RhcnRfZWxldmF0aW9uKSAlPiUgCiAgZGlzdGluY3Qoc3RhcnRfc3RhdGlvbl9pZCwgLmtlZXBfYWxsID0gVFJVRSkKYGBgCgoKYGBge3J9CgojIGNyZWF0ZSBjdXN0b20gaWNvbiBmb3IgYmlrZSBoaXJlIHN0YXRpb25zCmJpa2UgIDwtICBtYWtlSWNvbigiLi4vd3d3L2JpY3ljbGUtb3V0bGluZS5wbmciKQoKIyBtYXAgc3RhdGlvbiBkYXRhIHVzaW5nIGxlYWZsZXQgYXBwCm1hcF9kYXRhICU+JSAKICBsZWFmbGV0KCkgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JSAKICBhZGRUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgYWRkTWFya2Vycyh+c3RhcnRfc3RhdGlvbl9sb25naXR1ZGUsIH5zdGFydF9zdGF0aW9uX2xhdGl0dWRlLCAKICAgICAgICAgICAgIGljb24gPSB+YmlrZSwKICAgICAgICAgICAgICNjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCksCiAgICAgICAgICAgICBwb3B1cCA9IH5wYXN0ZTAoIlN0YXRpb24gSUQ6ICIsIHN0YXJ0X3N0YXRpb25faWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+TmFtZTogIiwgc3RhcnRfc3RhdGlvbl9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkVsZXZhdGlvbiAobSk6ICIsIHN0YXJ0X2VsZXZhdGlvbikpCgogICMgYWRkQ2lyY2xlcyhsbmcgPSB+c3RhcnRfc3RhdGlvbl9sb25naXR1ZGUsCiAgIyAgICAgICAgICAgIGxhdCA9IH5zdGFydF9zdGF0aW9uX2xhdGl0dWRlLAogICMgICAgICAgICAgICBjb2xvciA9ICIjRjI3RjFCIiwKICAjICAgICAgICAgICAgcG9wdXAgPSB+cGFzdGUwKCJTdGF0aW9uIElEOiAiLCBzdGFydF9zdGF0aW9uX2lkLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5OYW1lOiAiLCBzdGFydF9zdGF0aW9uX25hbWUsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkVsZXZhdGlvbiAobSk6ICIsIHN0YXJ0X2VsZXZhdGlvbikpCmBgYAoKIyMjIE1vc3QgcG9wdWxhciBzdGF0aW9ucwoKCmBgYHtyfQojIHRvcCAxMCBzdGFydCBhbmQgZW5kIHN0YXRpb25zCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIHNlbGVjdChzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9zdGF0aW9uX25hbWUsIHN0YXJ0X3N0YXRpb25fZGVzY3JpcHRpb24sIHN0YXJ0X2VsZXZhdGlvbikgJT4lIAogIGNvdW50KHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X3N0YXRpb25fbmFtZSwgc3RhcnRfc3RhdGlvbl9kZXNjcmlwdGlvbiwgc3RhcnRfZWxldmF0aW9uKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUgCiAgaGVhZCgxMCkKCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIHNlbGVjdChlbmRfc3RhdGlvbl9pZCwgZW5kX3N0YXRpb25fbmFtZSwgZW5kX3N0YXRpb25fZGVzY3JpcHRpb24sIGVuZF9lbGV2YXRpb24pICU+JSAKICBjb3VudChlbmRfc3RhdGlvbl9pZCwgZW5kX3N0YXRpb25fbmFtZSwgZW5kX3N0YXRpb25fZGVzY3JpcHRpb24sIGVuZF9lbGV2YXRpb24pICU+JSAKICBhcnJhbmdlKGRlc2MobikpICU+JQogIGhlYWQoMTApCmBgYAoKCmBgYHtyfQojIHJvdW5kIHRyaXAgdnMgYSB0byBiIGpvdXJuZXkKaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgZmlsdGVyKHN0YXJ0X3N0YXRpb25faWQgPT0gZW5kX3N0YXRpb25faWQpICU+JSAKICBjb3VudCgpCgpoaXJlc18yMDE5X2NsZWFuICU+JSAKICBmaWx0ZXIoc3RhcnRfc3RhdGlvbl9pZCAhPSBlbmRfc3RhdGlvbl9pZCkgJT4lIAogIGNvdW50KCkKCmBgYAoKCmBgYHtyfQojIG1hcCBtb3N0IHBvcHVsYXIgc3RhdGlvbnMgZGF0YSB1c2luZyBsZWFmbGV0IGFwcAptYXBfZGF0YSAlPiUgCiAgZmlsdGVyKHN0YXJ0X3N0YXRpb25faWQgJWluJSBjKCIyNDgiLCAiMjU5IiwgIjI2NSIsICIyODkiLCAiMjU3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNDkiLCAiMjQ3IiwgIjE3MSIsICIxODMiLCAiMjYyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNTAiLCAiMzU4IiwgIjI1OCIpKSAlPiUKICBsZWFmbGV0KCkgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JSAKICBhZGRUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgYWRkTWFya2Vycyh+c3RhcnRfc3RhdGlvbl9sb25naXR1ZGUsIH5zdGFydF9zdGF0aW9uX2xhdGl0dWRlLCAKICAgICAgICAgICAgIGljb24gPSB+YmlrZSwKICAgICAgICAgICAgIHBvcHVwID0gfnBhc3RlMCgiU3RhdGlvbiBJRDogIiwgc3RhcnRfc3RhdGlvbl9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPk5hbWU6ICIsIHN0YXJ0X3N0YXRpb25fbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkVsZXZhdGlvbiAobSk6ICIsIHN0YXJ0X2VsZXZhdGlvbikpCgpgYGAKCmBgYHtyfQptYXBfZGF0YSAlPiUgCiAgZmlsdGVyKHN0YXJ0X3N0YXRpb25faWQgJWluJSBjKCIyNDgiLCAiMjU5IiwgIjI2NSIsICIyODkiLCAiMjU3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNDkiLCAiMjQ3IiwgIjE3MSIsICIxODMiLCAiMjYyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNTAiLCAiMzU4IiwgIjI1OCIpKSAlPiUgCiAgZ2dwbG90KGxhYmVsID0gc3RhcnRfc3RhdGlvbl9pZCkgKwogIGdlb21fcG9pbnQoYWVzKHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2VsZXZhdGlvbikpICsKICB0aGVtZV9idygpICsKICBnZW9tX3RleHQoYWVzKHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2VsZXZhdGlvbiwgbGFiZWwgPSBzdGFydF9lbGV2YXRpb24sIGhqdXN0PS0wLjIsIHZqdXN0PTApKQoKYGBgCgpgYGB7cn0KbGlicmFyeShtYXBkZWNrKQoKc2V0X3Rva2VuKCJway5leUoxSWpvaWFtSTNOQ0lzSW1FaU9pSmpiRE40Tm01Mk9HTXdaM3BuTTJOeGRIaGxNVGh4YW5BMEluMC5pRk5jT2d1VTZya1VRRWhHcnVxU0JnIikgICMjIHNldCB5b3VyIG1hcGJveCB0b2tlbiBoZXJlCiNzZXRfdG9rZW4oInBrLmV5SjFJam9pYW1JM05DSXNJbUVpT2lKamJETjRObTUyT0dNd1ozcG5NMk54ZEhobE1UaHhhbkEwSW4wLmlGTmNPZ3VVNnJrVVFFaEdydXFTQmciKSAgIyMgc2V0IHlvdXIgbWFwYm94IHRva2VuIGhlcmUKCiNtYXBkZWNrX3Rva2VucygpCgpoaXJlc18yMDE5X2NsZWFuICU+JSAKZmlsdGVyKHN0YXJ0X3N0YXRpb25faWQgJWluJSBjKCIyNDgiKSkgJT4lIAogIG5hLm9taXQoKSAlPiUgCm1hcGRlY2soc3R5bGUgPSBtYXBkZWNrX3N0eWxlKCdkYXJrJyksIHBpdGNoID0gNDUsCiAgICAgICAgbG9jYXRpb24gPSBjKDU1Ljk0MiwgLTMuMTk5KSklPiUKICBhZGRfYXJjKAogICAgICBsYXllcl9pZCA9ICdhcmNfbGF5ZXInCiAgICAsIG9yaWdpbiA9IGMoInN0YXJ0X3N0YXRpb25fbG9uZ2l0dWRlIiwgInN0YXJ0X3N0YXRpb25fbGF0aXR1ZGUiKQogICAgLCBkZXN0aW5hdGlvbiA9IGMoImVuZF9zdGF0aW9uX2xvbmdpdHVkZSIsICJlbmRfc3RhdGlvbl9sYXRpdHVkZSIpCiAgICAsIHN0cm9rZV9mcm9tX29wYWNpdHkgPSAxMDAKICAgICwgc3Ryb2tlX3RvX29wYWNpdHkgPSAxMDAKICAgICwgc3Ryb2tlX3dpZHRoID0gMwogICAgLCBzdHJva2VfZnJvbSA9ICIjRjI3RjFCIgogICAgLCBzdHJva2VfdG8gPSAiYmxhY2siCiAgKQoKIyIyNTkiLCAiMjY1IiwgIjI4OSIsICIyNTciLCAiMjQ5IiwgIjI0NyIsICIxNzEiLCAiMTgzIiwgIjI2MiIsICIyNTAiLCAiMzU4IiwgIjI1OCIKYGBgCgoKYGBge3J9CmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIHNlbGVjdChzdGFydF9zdGF0aW9uX2lkLCBlbmRfc3RhdGlvbl9pZCkgJT4lIAogIGZpbHRlcihzdGFydF9zdGF0aW9uX2lkID09IGMoIjI0OCIsICIyNTkiLCAiMjY1IiwgIjI4OSIsICIyNTciLCAiMjYyIiwgIjI0OSIsICIyNDciLCAiMTcxIiwgIjE4MyIpLCAKICAgICAgICAgZW5kX3N0YXRpb25faWQgPT0gYygiMjYyIiwgIjI1NyIsICIyNTAiLCAiMjY1IiwgIjI0OCIsICIzNTgiLCAiMjU5IiwgIjE4MyIsICIxNzEiLCAiMjU4IikpICU+JSAKICBjaG9yZERpYWdyYW0oc2NhbGUgPSBUUlVFKQogIApgYGAKCmBgYHtyfQojIEpvdXJuZXlzIGVuZGluZyBhdCBWaWN0b3JpYSBRdWF5CmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIGZpbHRlcihlbmRfc3RhdGlvbl9pZCA9PSAiMjUwIikgJT4lIAogIGNvdW50KCkKCiMgSm91cm5leXMgZW5kaW5nIGF0IFZpY3RvcmlhIFF1YXksIGJ5IHN0YXJ0IHN0YXRpb24KaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgZmlsdGVyKGVuZF9zdGF0aW9uX2lkID09ICIyNTAiKSAlPiUgCiAgY291bnQoc3RhcnRfc3RhdGlvbl9pZCkgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSkKCiMgSm91cm5leXMgZW5kaW5nIGF0IEdlb3JnZSBTcXVhcmUsIGJ5IHN0YXJ0IHN0YXRpb24KaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgZmlsdGVyKGVuZF9zdGF0aW9uX2lkID09ICIxNzEiKSAlPiUgCiAgY291bnQoc3RhcnRfc3RhdGlvbl9pZCkgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSkKCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIGZpbHRlcihzdGFydF9zdGF0aW9uX2lkID09ICIyNTkiKSAlPiUgCiAgY291bnQoZW5kX3N0YXRpb25faWQpICU+JSAKICBhcnJhbmdlKGRlc2MobikpCmBgYAoKCgpgYGB7cn0KaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgc2VsZWN0KHN0YXJ0X3N0YXRpb25faWQsIGVuZF9zdGF0aW9uX2lkKSAlPiUKICBmaWx0ZXIoc3RhcnRfc3RhdGlvbl9pZCA9PSBjKCIyNDgiLCAiMjU5IiwgIjI2NSIsICIyODkiLCAiMjU3IiwgIjI2MiIsICIyNDkiLCAiMjQ3IiwgIjE3MSIsICIxODMiKSwgCiAgICAgICAgIGVuZF9zdGF0aW9uX2lkID09IGMoIjI2MiIsICIyNTciLCAiMjUwIiwgIjI2NSIsICIyNDgiLCAiMzU4IiwgIjI1OSIsICIxODMiLCAiMTcxIiwgIjI1OCIpKSAlPiUgCiAgZ2dyYXBoKGxheW91dCA9ICJsaW5lYXIiKSArIAogIGdlb21fZWRnZV9hcmMoZWRnZV9jb2xvdXIgPSAiYmxhY2siLCBlZGdlX2FscGhhID0gMC4zLCBlZGdlX3dpZHRoID0gMC4yKSArCiAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gIiNGMjdGMUIiLCBzaXplID0gMTApICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWwgPSBGQUxTRSwgc2l6ZSA9IDMsIG51ZGdlX3kgPSAwLCBjb2xvdXIgPSAid2hpdGUiKSArCiAgbGFicyh0aXRsZSA9ICJKb3VybmV5cyBiZXR3ZWVuIG1vc3QgcG9wdWxhciBzdGF0aW9uc1xuXG4iKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQocmVwKDEsIDQpLCAiY20iKSkKYGBgCgoKIyMjIEpvdXJuZXlzIGJhc2VkIG9uIGVsZXZhdGlvbgoKNjg2MjIgZG93bmhpbGwgam91cm5leXMKNDM3NzQgdXBoaWxsIGpvdXJuZXlzCjEyMDUwIGZsYXQgam91cm5leXMKCmBgYHtyfQojIGRvd25oaWxsIHZzIHVwaGlsbCB2cyBmbGF0IGpvdXJuZXlzCiMgYmFzZWQgb24gZWxldmF0aW9uIG9mIHN0YXJ0IGFuZCBlbmQgc3RhdGlvbnMKCiMgNjg2MjIgZG93bmhpbGwgam91cm5leXMKaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgZmlsdGVyKGVsZXZhdGlvbl9kaWZmIDwgMCkgJT4lIAogIGNvdW50KCkKCiMgNDM3NzQgdXBoaWxsIGpvdXJuZXlzCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIGZpbHRlcihlbGV2YXRpb25fZGlmZiA+IDApICU+JSAKICBjb3VudCgpCgojIDEyMDUwIGZsYXQgam91cm5leXMKaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgZmlsdGVyKGVsZXZhdGlvbl9kaWZmID09IDApICU+JSAKICBjb3VudCgpCmBgYApgYGB7cn0KZ2V0X2VsZXZfcmFzdGVyKCkKYGBgCgoKCiMjIyBKb3VybmV5cyBiYXNlZCBvbiB3ZWF0aGVyCgpBY2NvcmRpbmcgdG8gd3d3LnN0YXRpc3RhLmNvbSAiQSByYWluZGF5IGlzIHdoZW4gb25lIG1pbGxpbWV0cmUgb3IgbW9yZSBvZiByYWluIG9jY3VycyBpbiBhIGRheS4iIEJhc2VkIG9uIHRoaXMgSSBoYXZlIGNsYXNzaWZpZWQgcmFpbnkgZGF5cyBhcyBkYXlzIHdoZXJlIHJhaW5mYWxsIGFzIHJlY29yZGVkIGJ5IHd3dy5wb3dlci5sYXJjLm5hc2EuZ292LyB3YXMgZXF1YWwgdG8gb3Igb3ZlciAxbW0gaW4gRWRpbmJ1cmdoLgoKCmBgYHtyfQpoaXJlc18yMDE5X2NsZWFuICU+JSAKICBzZWxlY3Qoc3RhcnRfZGF0ZSwgcmFpbmZhbGxfbW0pICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyhzdGFydF9kYXRlLCByYWluZmFsbF9tbSksIGNvbCA9ICJibHVlIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGNvbD0iI0YyN0YxQiIpICsKICBsYWJzKHggPSAiXG5EYXRlIiwKICAgICAgIHkgPSAiUmFpbmZhbGwgKG1tKVxuIiwKICAgICAgIHRpdGxlID0gIkVkaW5idXJnaCdzIGRhaWx5IHJhaW5mYWxsIGluIDIwMTkiLAogICAgICAgc3VidGl0bGUgPSAiKE9yYW5nZSBsaW5lIGF0IDFtbSwgYWJvdmUgd2hpY2ggd2UgY2xhc3MgYXMgcmFpbnkgZGF5KVxuIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUodGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkKYGBgCgojIyMgSHlwb3RoZXNpcyBUZXN0CgpgYGB7cn0KIyBJbmRlcGVuZGVuY2UgSHlwb3RoZXNpcwojIM6xID0gMC4wNQojIEgwIC0gdXBoaWxsIGpvdXJuZXlzIG1ha2VzIG5vIGRpZmZlcmVuY2UgdG8gYmlrZSBoaXJlcwojIEgxIC0gdXBoaWxsIGpvdXJuZXlzIGhhdmUgYW4gaW1wYWN0IG9uIGJpa2UgaGlyZXMKCiMgb3JnYW5pc2UgdGhlIGRhdGEgc28gSSBoYXZlIGFuIHVwaGlsbCBjb2x1bW4gd2l0aCBhIGxvZ2ljYWwgb3V0cHV0IFRSVUUvRkFMU0UgaWYgdGhlIGVsZXZhdGlvbiBjaGFuZ2Ugd2FzIHBvc2l0aXZlCiMgYWxzbyBjb3VudCB0aGUgbnVtYmVyIG9mIGpvdXJuZXlzIHRoYXQgb2NjdXJyZWQgb24gZWFjaCBkYXkKdXBoaWxsIDwtIGhpcmVzXzIwMTlfY2xlYW4gJT4lCiAgZ3JvdXBfYnkoc3RhcnRfZGF0ZSkgJT4lIAogIG11dGF0ZSh1cGhpbGwgPSBlbGV2YXRpb25fZGlmZiA+IDApICU+JQogIHNlbGVjdChzdGFydF9kYXRlLCB1cGhpbGwpICU+JSAKICBjb3VudChzdGFydF9kYXRlLCB1cGhpbGwpCgojIGNyZWF0ZSBhIG51bGwgZGlzdHJpYnV0aW9uIHBlcm11dGluZyB0aGUgVHJ1ZSBhbmQgRmFsc2UgdmFsdWVzIG9uIHdoZXRoZXIgdGhlIGpvdXJuZXkgd2FzIHVwaGlsbCBvciBub3QKIyBkbyAxMGsgcmVwcyBhbmQgY2hlY2sgdGhlIGRpZmZlcmVuY2UgaW4gbWVhbnMgb2YgdGhlIGdyb3VwcwpudWxsX2Rpc3RyaWJ1dGlvbiA8LSB1cGhpbGwgJT4lIAogIHNwZWNpZnkobiB+IHVwaGlsbCkgJT4lCiAgaHlwb3RoZXNpemUobnVsbCA9ICJpbmRlcGVuZGVuY2UiKSAlPiUgCiAgZ2VuZXJhdGUocmVwcyA9IDEwMDAwLCB0eXBlID0gInBlcm11dGUiKSAlPiUgCiAgY2FsY3VsYXRlKHN0YXQgPSAiZGlmZiBpbiBtZWFucyIsIG9yZGVyID0gYygiVFJVRSIsICJGQUxTRSIpKSAKCiMgY3JlYXRlIGFuIG9ic2VydmVkIHN0YXQKb2JzZXJ2ZWRfc3RhdCA8LSB1cGhpbGwgJT4lIAogIHNwZWNpZnkobiB+IHVwaGlsbCkgJT4lCiAgY2FsY3VsYXRlKHN0YXQgPSAiZGlmZiBpbiBtZWFucyIsIG9yZGVyID0gYygiVFJVRSIsICJGQUxTRSIpKSAKCiMgcGxvdCBvYnNlcnZlZCBzdGF0IG9uIHRoZSBudWxsIGRpc3RyaWJ1dGlvbgpudWxsX2Rpc3RyaWJ1dGlvbiAlPiUKICB2aXN1YWxpc2UoKSArCiAgc2hhZGVfcF92YWx1ZShvYnNfc3RhdCA9IG9ic2VydmVkX3N0YXQsIGRpcmVjdGlvbiA9ICJsZWZ0IikKCiMgY2FsY3VsYXRlIHRoZSBwLXZhbHVlIGFuZCBjb21wYXJlIHRvIM6xIHZhbHVlCnBfdmFsdWUgPC0gbnVsbF9kaXN0cmlidXRpb24gJT4lCiAgZ2V0X3BfdmFsdWUob2JzX3N0YXQgPSBvYnNlcnZlZF9zdGF0LCBkaXJlY3Rpb24gPSAibGVmdCIpCgpwX3ZhbHVlCmBgYAoKCmBgYHtyfQojIGh5cG90aGVzaXMgdGVzdAojIM6xID0gMC4wNQojIEgwIC0gUmFpbiBtYWtlcyBubyBkaWZmZXJlbmNlIHRvIGJpa2UgaGlyZXMKIyBIMSAtIFJhaW4gaGFzIGFuIGltcGFjdCBvbiBiaWtlIGhpcmVzCiMgVHlwZSBvZiB0ZXN0IGlzIG9uZS1zYW1wbGUgcHJvcG9ydGlvbiwgcmlnaHQtc2lkZWQuCiMgCiMgcCB2YWx1ZSA9IDAgCiMgCiMgVGhlIHAtdmFsdWUgYmVpbmcgbmVhciB0byAwIG1lYW5zIGl0IGlzIGxlc3MgdGhhbiDOsSwgYW5kIHNvIHdlIHNob3VsZCByZWplY3QgSDAgYmFzZWQgb24gb3VyIGRhdGEuIFRoZSByZXN1bHQgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBpbiBmYXZvdXIgb2YgSDEsIHRoYXQgcmFpbiBtYXkgaW1wYWN0IGJpa2UgaGlyZSBudW1iZXJzLgoKIyByYWluX2RheSA8LSBoaXJlc18yMDE5X2NsZWFuICU+JQojICAgZ3JvdXBfYnkoc3RhcnRfZGF0ZSkgJT4lIAojICAgbXV0YXRlKHJhaW5fZGF5ID0gcmFpbmZhbGxfbW0gPj0gMSkgJT4lIAojICAgc2VsZWN0KHN0YXJ0X2RhdGUsIHJhaW5fZGF5KSAlPiUgCiMgICBjb3VudChzdGFydF9kYXRlLCByYWluX2RheSkKIyAKIyBudWxsX2Rpc3RyaWJ1dGlvbiA8LSByYWluX2RheSAlPiUKIyAgIHNwZWNpZnkocmVzcG9uc2UgPSByYWluX2RheSwgc3VjY2VzcyA9ICJUUlVFIikgJT4lCiMgICBoeXBvdGhlc2l6ZShudWxsID0gInBvaW50IiwgcCA9IDAuMDUpICU+JQojICAgZ2VuZXJhdGUocmVwcyA9IDEwMDAwLCB0eXBlID0gImRyYXciKSAlPiUKIyAgIGNhbGN1bGF0ZShzdGF0ID0gInByb3AiKQojIAojIG9ic19zdGF0IDwtIHJhaW5fZGF5ICU+JQojICAgc3BlY2lmeShyZXNwb25zZSA9IHJhaW5fZGF5LCBzdWNjZXNzID0gIlRSVUUiKSAlPiUKIyAgIGNhbGN1bGF0ZShzdGF0ID0gInByb3AiKQojIAojIG51bGxfZGlzdHJpYnV0aW9uICU+JQojICAgdmlzdWFsaXNlKCkgKwojICAgc2hhZGVfcF92YWx1ZShkaXJlY3Rpb24gPSAicmlnaHQiLCBvYnNfc3RhdCA9IG9ic19zdGF0KQojIAojIG51bGxfZGlzdHJpYnV0aW9uICU+JQojICAgZ2V0X3BfdmFsdWUoZGlyZWN0aW9uID0gInJpZ2h0Iiwgb2JzX3N0YXQgPSBvYnNfc3RhdCkKCmBgYAoKYGBge3J9CiMgYm9vdHN0cmFwcGVkIGh5cG90aGVzaXMKIyDOsSA9IDAuMDUKIyBIMCAtIFJhaW4gbWFrZXMgbm8gZGlmZmVyZW5jZSB0byBiaWtlIGhpcmVzCiMgSDEgLSBSYWluIGhhcyBhbiBpbXBhY3Qgb24gYmlrZSBoaXJlcwoKIyByYWluX2RheV9mbGFnIDwtIHJhaW5fZGF5ICU+JQojICAgbXV0YXRlKHJhaW5fZGF5X2ZsYWcgPSBpZl9lbHNlKHJhaW5fZGF5ID09ICJUUlVFIiwgMSwgMCkpCiMgCiMgbnVsbF9kaXN0cmlidXRpb24gPC0gcmFpbl9kYXlfZmxhZyAlPiUKIyAgIHNwZWNpZnkocmVzcG9uc2UgPSByYWluX2RheV9mbGFnKSAlPiUKIyAgIGh5cG90aGVzaXplKG51bGwgPSAicG9pbnQiLCBtdSA9IDAuMDUpICU+JQojICAgZ2VuZXJhdGUocmVwcyA9IDEwMDAwLCB0eXBlID0gImJvb3RzdHJhcCIpICU+JQojICAgY2FsY3VsYXRlKHN0YXQgPSAibWVhbiIpCiMgCiMgbnVsbF9kaXN0cmlidXRpb24gJT4lCiMgICB2aXN1YWxpc2UoKSArCiMgICBzaGFkZV9wX3ZhbHVlKGRpcmVjdGlvbiA9ICJyaWdodCIsIG9ic19zdGF0ID0gb2JzX3N0YXQpCiMgCiMgbnVsbF9kaXN0cmlidXRpb24gJT4lCiMgICBnZXRfcF92YWx1ZShkaXJlY3Rpb24gPSAicmlnaHQiLCBvYnNfc3RhdCA9IG9ic19zdGF0KQpgYGAKCiMjIyBJbmRlcGVuZGVuY2UgSHlwb3RoZXNpcyBUZXN0IE9uIFJhaW55IGRheSBkYXRhCgpEb2VzIGEgcmFpbnkgZGF5IGhhdmUgYW4gZWZmZWN0IG9uIGJpa2UgaGlyZXMKCs6xID0gMC4wNQpIMCAtIFJhaW4gbWFrZXMgbm8gZGlmZmVyZW5jZSB0byBiaWtlIGhpcmVzCkgxIC0gUmFpbiBoYXMgYW4gaW1wYWN0IG9uIGJpa2UgaGlyZXMKClRoZSBwLXZhbHVlIOKJpCDOsSwgc28gSSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBIMCBpbiBmYXZvdXIgb2YgdGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgSDEsIAp0aGF0IHJhaW4gX21heV8gaGF2ZSBhbiBlZmZlY3Qgb24gYmlrZSBoaXJlcy4KCmBgYHtyfQojIEluZGVwZW5kZW5jZSBIeXBvdGhlc2lzCiMgzrEgPSAwLjA1CiMgSDAgLSBSYWluIG1ha2VzIG5vIGRpZmZlcmVuY2UgdG8gYmlrZSBoaXJlcwojIEgxIC0gUmFpbiBoYXMgYW4gaW1wYWN0IG9uIGJpa2UgaGlyZXMKCiMgb3JnYW5pc2UgdGhlIGRhdGEgc28gSSBoYXZlIGEgcmFpbl9kYXkgY29sdW1uIHdpdGggYSBsb2dpY2FsIG91dHB1dCBUUlVFL0ZBTFNFIGlmIGl0IHJhaW5lZCB0aGF0IGRheQojIGFsc28gY291bnQgdGhlIG51bWJlciBvZiBqb3VybmV5cyB0aGF0IG9jY3VycmVkIG9uIGVhY2ggZGF5CnJhaW5fZGF5IDwtIGhpcmVzXzIwMTlfY2xlYW4gJT4lCiAgZ3JvdXBfYnkoc3RhcnRfZGF0ZSkgJT4lIAogIG11dGF0ZShyYWluX2RheSA9IHJhaW5mYWxsX21tID49IDEpICU+JSAKICBzZWxlY3Qoc3RhcnRfZGF0ZSwgcmFpbl9kYXkpICU+JSAKICBjb3VudChzdGFydF9kYXRlLCByYWluX2RheSkKCiMgY3JlYXRlIGEgbnVsbCBkaXN0cmlidXRpb24gcGVybXV0aW5nIHRoZSBUcnVlIGFuZCBGYWxzZSB2YWx1ZXMgb24gd2hldGhlciBpdCByYWluZWQKIyBkbyAxMGsgcmVwcyBhbmQgY2hlY2sgdGhlIGRpZmZlcmVuY2UgaW4gbWVhbnMgb2YgdGhlIGdyb3VwcwpudWxsX2Rpc3RyaWJ1dGlvbiA8LSByYWluX2RheSAlPiUgCiAgc3BlY2lmeShuIH4gcmFpbl9kYXkpICU+JQogIGh5cG90aGVzaXplKG51bGwgPSAiaW5kZXBlbmRlbmNlIikgJT4lIAogIGdlbmVyYXRlKHJlcHMgPSAxMDAwMCwgdHlwZSA9ICJwZXJtdXRlIikgJT4lIAogIGNhbGN1bGF0ZShzdGF0ID0gImRpZmYgaW4gbWVhbnMiLCBvcmRlciA9IGMoIlRSVUUiLCAiRkFMU0UiKSkgCgojIGNyZWF0ZSBhbiBvYnNlcnZlZCBzdGF0Cm9ic2VydmVkX3N0YXQgPC0gcmFpbl9kYXkgJT4lIAogIHNwZWNpZnkobiB+IHJhaW5fZGF5KSAlPiUKICBjYWxjdWxhdGUoc3RhdCA9ICJkaWZmIGluIG1lYW5zIiwgb3JkZXIgPSBjKCJUUlVFIiwgIkZBTFNFIikpIAoKIyBwbG90IG9ic2VydmVkIHN0YXQgb24gdGhlIG51bGwgZGlzdHJpYnV0aW9uCm51bGxfZGlzdHJpYnV0aW9uICU+JQogIHZpc3VhbGlzZSgpICsKICBzaGFkZV9wX3ZhbHVlKG9ic19zdGF0ID0gb2JzZXJ2ZWRfc3RhdCwgZGlyZWN0aW9uID0gImxlZnQiKQoKIyBjYWxjdWxhdGUgdGhlIHAtdmFsdWUgYW5kIGNvbXBhcmUgdG8gzrEgdmFsdWUKcF92YWx1ZSA8LSBudWxsX2Rpc3RyaWJ1dGlvbiAlPiUKICBnZXRfcF92YWx1ZShvYnNfc3RhdCA9IG9ic2VydmVkX3N0YXQsIGRpcmVjdGlvbiA9ICJsZWZ0IikKCnBfdmFsdWUKCmBgYAoKUmFpbnkgRGF5cyBpbiAyMDE5ID0gMTgxClJhaW55IGpvdXJuZXlzID0gNTgwNzMKTm9uIHJhaW55IGpvdXJuZXlzID0gNjYzNzMKCmBgYHtyfQojIGNvdW50IHRoZSBudW1iZXIgb2YgZGF5cyB3aXRoIHJhaW5mYWxsIGVxdWFsIHRvIG9yIG92ZXIgMW1tCnJhaW5fMjAxOV9jbGVhbiAlPiUgCiAgZmlsdGVyKHJhaW5mYWxsX21tID49IDEpICU+JSAKICBjb3VudCgpCgojIGpvdXJuZXlzIGJhc2VkIG9uIHJhaW5mYWxsCiMgYmFzZWQgb24gZGFpbHkgcHJlY2lwaXRhdGlvbgpoaXJlc18yMDE5X2NsZWFuICU+JSAKICBmaWx0ZXIocmFpbmZhbGxfbW0gPj0gMSkgJT4lIAogIGNvdW50KCkKCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIGZpbHRlcihyYWluZmFsbF9tbSA8IDEpICU+JSAKICBjb3VudCgpCmBgYAoKCiMjIyBUaW1lIG9mIERheSBhbmFseXNpcwoKR3ltIEJ1bm5pZXMgLSBiZWZvcmUgN2FtOiAgICAgICAgICAgNzc4MyAgIDIzLjA3IG1pbnMgICAKTW9ybmluZyBDb21tdXRlcnMgLSA3YW0gdG8gOWFtOiAgICAgMTI0NTIgIDE3Ljg3IG1pbnMgICAgCkRheSBUcmlwcGVycyAtIDlhbSB0byA1cG06ICAgICAgICAgIDY2ODgwICAyOS43NSBtaW5zICAgIApIb21ld2FyZCBCb3VuZGVycyAtIDVwbSB0byA2LjMwcG06ICAxNDk2MSAgMjMuODYgbWlucyAgICAKRXZlbmluZyBNb3ZlcnMgLSA2LjMwcG0gdG8gMTBwbTogICAgMTY4MTUgIDIzLjUgbWlucyAgICAKUHViIFBvbmllcyAtIDEwcG0gdG8gTWlkbmlnaHQ6ICAgICAgNTU1NSAgIDIwLjY3IG1pbnMgICAKCkF2ZXJhZ2Ugam91cm5leSB0aW1lIG92ZXJhbGwgaXMgMjYuMTggbWludXRlcwoKYGBge3J9CiMgR3ltIEJ1bm5pZXMgLSBiZWZvcmUgN2FtCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIG11dGF0ZShzdGFydF90aW1lID0gYXMuY2hhcmFjdGVyKHN0YXJ0X3RpbWUpLCBlbmRfdGltZSA9IGFzLmNoYXJhY3RlcihlbmRfdGltZSkpICU+JSAKICBmaWx0ZXIoc3RhcnRfdGltZSA8PSAiMDc6MDA6MDAiKSAlPiUgCiAgbXV0YXRlKG1lYW5fZHVyYXRpb24gPSByb3VuZChtZWFuKGR1cmF0aW9uKSwgMikpICU+JSAKICBjb3VudChtZWFuX2R1cmF0aW9uKQoKIyBNb3JuaW5nIENvbW11dGVycyAtIDdhbSB0byA5YW0KaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgbXV0YXRlKHN0YXJ0X3RpbWUgPSBhcy5jaGFyYWN0ZXIoc3RhcnRfdGltZSksIGVuZF90aW1lID0gYXMuY2hhcmFjdGVyKGVuZF90aW1lKSkgJT4lIAogIGZpbHRlcihzdGFydF90aW1lID4gIjA3OjAwOjAwIiwgc3RhcnRfdGltZSA8PSAiMDk6MDA6MDAiKSAlPiUgCiAgbXV0YXRlKG1lYW5fZHVyYXRpb24gPSByb3VuZChtZWFuKGR1cmF0aW9uKSwgMikpICU+JSAKICBjb3VudChtZWFuX2R1cmF0aW9uKQoKIyBEYXkgVHJpcHBlcnMgLSA5YW0gdG8gNXBtCmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIG11dGF0ZShzdGFydF90aW1lID0gYXMuY2hhcmFjdGVyKHN0YXJ0X3RpbWUpLCBlbmRfdGltZSA9IGFzLmNoYXJhY3RlcihlbmRfdGltZSkpICU+JSAKICBmaWx0ZXIoc3RhcnRfdGltZSA+ICIwOTowMDowMCIsIHN0YXJ0X3RpbWUgPCAiMTc6MDA6MDAiKSAlPiUgCiAgbXV0YXRlKG1lYW5fZHVyYXRpb24gPSByb3VuZChtZWFuKGR1cmF0aW9uKSwgMikpICU+JSAKICBjb3VudChtZWFuX2R1cmF0aW9uKQoKIyBIb21ld2FyZCBCb3VuZGVycyAtIDVwbSB0byA2LjMwcG0KaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgbXV0YXRlKHN0YXJ0X3RpbWUgPSBhcy5jaGFyYWN0ZXIoc3RhcnRfdGltZSksIGVuZF90aW1lID0gYXMuY2hhcmFjdGVyKGVuZF90aW1lKSkgJT4lIAogIGZpbHRlcihzdGFydF90aW1lID49ICIxNzowMDowMCIsIHN0YXJ0X3RpbWUgPD0gIjE4OjMwOjAwIikgJT4lIAogIG11dGF0ZShtZWFuX2R1cmF0aW9uID0gcm91bmQobWVhbihkdXJhdGlvbiksIDIpKSAlPiUgCiAgY291bnQobWVhbl9kdXJhdGlvbikKCiMgRXZlbmluZyBNb3ZlcnMgLSA2LjMwcG0gdG8gMTBwbQpoaXJlc18yMDE5X2NsZWFuICU+JSAKICBtdXRhdGUoc3RhcnRfdGltZSA9IGFzLmNoYXJhY3RlcihzdGFydF90aW1lKSwgZW5kX3RpbWUgPSBhcy5jaGFyYWN0ZXIoZW5kX3RpbWUpKSAlPiUgCiAgZmlsdGVyKHN0YXJ0X3RpbWUgPiAiMTg6MzA6MDAiLCBzdGFydF90aW1lIDwgIjIyOjAwOjAwIikgJT4lIAogIG11dGF0ZShtZWFuX2R1cmF0aW9uID0gcm91bmQobWVhbihkdXJhdGlvbiksIDIpKSAlPiUgCiAgY291bnQobWVhbl9kdXJhdGlvbikKCiMgUHViIFBvbmllcyAtIDEwcG0gdG8gTWlkbmlnaHQKaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgbXV0YXRlKHN0YXJ0X3RpbWUgPSBhcy5jaGFyYWN0ZXIoc3RhcnRfdGltZSksIGVuZF90aW1lID0gYXMuY2hhcmFjdGVyKGVuZF90aW1lKSkgJT4lIAogIGZpbHRlcihzdGFydF90aW1lID49ICIyMjowMDowMCIpICU+JSAKICBtdXRhdGUobWVhbl9kdXJhdGlvbiA9IHJvdW5kKG1lYW4oZHVyYXRpb24pLCAyKSkgJT4lIAogIGNvdW50KG1lYW5fZHVyYXRpb24pCgojIEF2ZXJhZ2Ugam91cm5leSBsZW5ndGgKaGlyZXNfMjAxOV9jbGVhbiAlPiUgCiAgbXV0YXRlKG1lYW5fZHVyYXRpb24gPSByb3VuZChtZWFuKGR1cmF0aW9uKSwgMikpICU+JSAKICBjb3VudChtZWFuX2R1cmF0aW9uKQoKYGBgCgoKYGBge3J9CmhpcmVzXzIwMTlfY2xlYW4gJT4lIAogIHNlbGVjdChzdGFydF90aW1lKSAlPiUKICBncm91cF9ieShzdGFydF90aW1lKSAlPiUgCiAgY291bnQoKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyhzdGFydF90aW1lLCBuKSwgY29sID0gIiNGMjdGMUIiKSArCiAgbGFicyh4ID0gIlxuVGltZSBvZiBEYXkiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgSm91cm5leXNcbiIsCiAgICAgICB0aXRsZSA9ICJTdGFydCB0aW1lIG9mIGpvdXJuZXlzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUodGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkKYGBgCgpgYGB7cn0KIyB0cnlpbmcgYSByYXN0ZXIgaW1hZ2Ugb2YgZWxldmF0aW9uCmdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gbmV3X2VsZXZhdGlvbl9yYXN0ZXIsIGFlcyh4ID0geCwgeSA9IHkpKSArCiAgZ2VvbV9zZihkYXRhID0gZWxldmF0aW9uX3Jhc3RlciwgY29sb3IgPSAid2hpdGUiKSArCiAgY29vcmRfc2YoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgbGFicyh0aXRsZSA9ICIgIiwgeCA9ICIgIiwgeSA9ICIgIiwgZmlsbCA9ICIgIikKYGBgCgo=